package com.dycong.common.common;

import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.net.ftp.*;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.Objects;

/**
 * @author dycong
 * @date 2019/10/11 15:20
 */
@Log4j2
public class FTPSUtil {

    private static final String LOGGER_PREFIX = "FTP ";
    private static final String UTF_8 = "UTF-8";

    private FTPSClient ftpClient;

    private FTPSUtil() {
    }

    public static FTPSUtil instance(String ftpHost, String ftpUser,
                                    String ftpPw, int ftpPort) throws IOException {
        FTPSClient ftpClient = new FTPSClient();
        // 连接FTP服务器
        ftpClient.connect(ftpHost, ftpPort);
        // 登陆FTP服务器
        ftpClient.login(ftpUser, ftpPw);
        if (!FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {
            log.error(LOGGER_PREFIX + "连接 FTP 失败:{}", ftpClient.getReplyString());
            ftpClient.disconnect();
        }
        log.info(LOGGER_PREFIX + "连接 FTP 成功 ftpHost:{},reply:{}", ftpHost, ftpClient.getReplyString());

        FTPSUtil ftpsUtil = new FTPSUtil();
        ftpsUtil.ftpClient = ftpClient;

        configClient(ftpsUtil);
        return ftpsUtil;
    }


    private static void configClient(FTPSUtil ftpsUtil) throws IOException {
        ftpsUtil.ftpClient.setControlEncoding(UTF_8);
        ftpsUtil.ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
        ftpsUtil.ftpClient.enterLocalPassiveMode();
        ftpsUtil.ftpClient.setFileTransferMode(FTP.STREAM_TRANSFER_MODE);
        ftpsUtil.ftpClient.execPROT("P");
    }

    /**
     * 从FTP服务器下载文件
     *
     * @param ftpPath     FTP服务器中文件所在路径 格式： ftptest/aa
     * @param fileToPath  下载到本地的位置 格式：H:/download
     * @param ftpFileName 文件名称
     */
    public boolean downloadFtpFile(String ftpPath, String fileToPath, String ftpFileName) {
        OutputStream os = null;
        try {
            if (!isFTPFileExist(ftpFileName, ftpPath)) {
                return false;
            }

            // 进入文件所在目录，注意编码格式，以能够正确识别中文目录
            ftpClient.changeWorkingDirectory(new String(ftpPath.getBytes(StandardCharsets.UTF_8),
                    FTP.DEFAULT_CONTROL_ENCODING));

            File localFile = new File(fileToPath + File.separatorChar + ftpFileName);
            os = new FileOutputStream(localFile);

            return ftpClient.retrieveFile(ftpFileName, os);
        } catch (IOException e) {
            log.error(LOGGER_PREFIX + "downloadFtpFile error ftpPath:{},ftpFileName:{},fileToPath:{}", ftpPath, ftpFileName, fileToPath, e);
            return false;
        } finally {
            try {
                if (Objects.nonNull(os)) {
                    os.flush();
                    os.close();
                    close();
                }
            } catch (IOException ignore) {
            }
        }
    }


    /**
     * @param ftpPath     FTP服务器中文件所在路径 格式： ftptest/aa
     * @param ftpFileName 文件名称
     * @see 读取完后 调用方需要 调用 FTPSUtil#close()，及 close BufferedReader
     */
    public BufferedReader downloadFtpFile(String ftpPath, String ftpFileName) throws IOException {
        try {
            if (!isFTPFileExist(ftpFileName, ftpPath)) {
                throw new FileNotFoundException();
            }

            // 进入文件所在目录，注意编码格式，以能够正确识别中文目录
            ftpClient.changeWorkingDirectory(new String(ftpPath.getBytes(StandardCharsets.UTF_8),
                    FTP.DEFAULT_CONTROL_ENCODING));


            InputStream inputStream = ftpClient.retrieveFileStream(new String(ftpFileName
                    .getBytes(StandardCharsets.UTF_8), FTP.DEFAULT_CONTROL_ENCODING));

            if (inputStream == null || ftpClient.getReplyCode() == FTPReply.FILE_UNAVAILABLE) {
                //550) 文件不可用(例如，未找到文件，无法访问文件)
                log.info(LOGGER_PREFIX + "isFileExist -{}/{} reply:{}", ftpPath, ftpFileName, ftpClient.getReplyString());
                throw new FileNotFoundException(ftpClient.getReplyString());
            }
            Reader reader = new InputStreamReader(inputStream);
            return new BufferedReader(reader);
        } catch (IOException e) {
            log.error(LOGGER_PREFIX + "downloadFtpFile error ftpPath:{},ftpFileName:{},fileToPath:{}", ftpPath, ftpFileName, e);
            throw e;
        }
    }


    /**
     * 方法描述：检验指定路径的文件是否存在ftp服务器中
     *
     * @param ftpPath 指定绝对路径的文件/TEST/20161010
     * @return 存在返回true，不存在返回false
     */
    public boolean isFTPFileExist(String ftpFileName, String ftpPath) throws IOException {
        if (StringUtils.isBlank(ftpFileName) || StringUtils.isBlank(ftpPath)) {
            return false;
        }
        // 进入文件所在目录，注意编码格式，以能够正确识别中文目录
        ftpClient.changeWorkingDirectory(new String(ftpPath.getBytes(StandardCharsets.UTF_8),
                FTP.DEFAULT_CONTROL_ENCODING));

        FTPFile[] ftpFiles = ftpClient.listFiles();
        for (FTPFile ftpFile : ftpFiles) {
            if (ftpFileName.equals(ftpFile.getName())) {
                return true;
            }
        }

        return false;
    }


    /**
     * 使用完毕，应该及时关闭连接
     * 终止 ftp 传输
     * 断开 ftp 连接
     */
    public void close() throws IOException {
        try {
            if (ftpClient != null && ftpClient.isConnected()) {
//                ftpClient.completePendingCommand();
                ftpClient.logout();
//                ftpClient.abort();
                ftpClient.disconnect();
            }
        } catch (IOException e) {
            log.error(LOGGER_PREFIX + "close error", e);
            throw e;
        }
    }


    /**
     * Description: 向FTP服务器上传文件
     *
     * @param ftpPath     FTP服务器中文件所在路径 格式： ftptest/aa
     * @param ftpFileName ftp文件名称
     * @param input       文件流
     * @return 成功返回true，否则返回false
     */
    public boolean uploadFile(String ftpPath,
                              String ftpFileName, InputStream input) {

        try {
            ftpClient.changeWorkingDirectory(ftpPath);
            boolean upload = ftpClient.storeFile(ftpFileName, input);
            log.info(LOGGER_PREFIX + "uploadFile -{}/{} reply:{}", ftpPath, ftpFileName, ftpClient.getReplyString());
            return upload;
        } catch (Exception e) {
            log.error(LOGGER_PREFIX + "uploadFile -{}/{} reply:{}", ftpPath, ftpFileName, ftpClient.getReplyString(), e);
            return false;
        }
    }


    public static void main(String[] args) throws IOException {

        String ftpHost = "test.hezuofang.ssjlicai.com";
        String ftpUserName = "payment2";
        String ftpPassword = "payment2";
        int ftpPort = 10022;
        String ftpPath = "/V2/2015";
        String localPath = "C:\\Users\\arlain\\Desktop\\新建文件夹";
        String fileName = "2019-10-10.txt";

        FTPSUtil ftpsUtil = FTPSUtil.instance(ftpHost, ftpUserName, ftpPassword, ftpPort);

      /*  boolean b = ftpsUtil.downloadFtpFile(ftpPath, localPath, fileName);
        System.out.println(b);*/



/*        BufferedReader bufferedReader = ftpsUtil.downloadFtpFile(ftpPath, fileName);
        String line = bufferedReader.readLine();
        while (Objects.nonNull(line)) {
            System.out.println(line);
            line = bufferedReader.readLine();
        }
        bufferedReader.close();
        ftpsUtil.close();*/

        FileInputStream inputStream = new FileInputStream(localPath + "\\" + fileName);
        boolean bb = ftpsUtil.uploadFile(ftpPath, fileName + "3", inputStream);
        System.out.println(bb);
        ftpsUtil.close();
        inputStream.close();
//        }
    }


}
